import { ImportMode } from '@/utils/interfaces'
import { compile } from '@/utils/js2ts'
import { mockToJsonSchema } from '@/utils/mock'
import { camelCase, lowerCase, upperFirst } from 'lodash-es'
import { sample } from 'openapi-sampler'

export const pascalCase = (str: string) => {
    return upperFirst(camelCase(str))
}

// 获取方法名
const getFuncNames = (apiItems: IApiItem[]) => {
    // funcName: id
    const funcNamesMap: Record<string, string> = {}
    apiItems.forEach((item) => {
        const url = item.url
        const splited = url?.split('/')
        if (!splited?.length) return 'Unknown'
        // 最终函数名称
        let funcName = pascalCase(splited.pop() || '')
        if (!funcName) return 'Unknown'
        // 如果已存在则往前取
        while (funcNamesMap[funcName]) {
            funcName += pascalCase(splited.pop() || '')
        }
        funcNamesMap[funcName] = item.id
    })
    // 转换成 id: funcName 对象
    const funcNames = Object.entries(funcNamesMap).map(([funcName, id]) => [
        id,
        funcName,
    ])
    return Object.fromEntries(funcNames)
}

// 获取reqBodySchema
export const getReqBodySchema = (item: IApiItem) => {
    // 请求参数的jsonSchema
    let reqBodySchema = {}
    // 如果有mockRule则转换为jsonSchema
    if (item.handlers?.reqBody?.mockRule) {
        reqBodySchema = mockToJsonSchema(item.handlers?.reqBody?.mockRule, item)
    }
    // 如果有导入时的数据，则使用导入时的数据
    const importData = item?.importData
    const importMode = importData?.mode
    if (importMode) {
        // 这是swagger导入的
        if (importMode === ImportMode.swaggerJsonUrl && importData?.pathItem) {
            const methodItem =
                importData?.pathItem[item?.importData?.method || '']
            if (
                methodItem &&
                methodItem?.requestBody?.content?.['application/json']?.schema
            ) {
                reqBodySchema =
                    methodItem?.requestBody?.content?.['application/json']
                        ?.schema
            }
        } else if (
            importMode === ImportMode.yapiUrl ||
            importMode === ImportMode.yapiPage
        ) {
            let schema = importData?.yapiItem?.req_body_other
            if (typeof schema === 'string') {
                try {
                    schema = JSON.parse(schema)
                } catch {}
            }
            if (schema && typeof schema !== 'string') {
                // 从yapi导入的
                reqBodySchema = schema
            }
        }
    }
    return reqBodySchema
}

// 获取resBodySchema
export const getResBodySchema = (item: IApiItem) => {
    // 响应体的jsonSchema
    let resBodySchema = {}
    // 如果有mockRule则转换为jsonSchema
    if (item.handlers?.resBody?.mockRule) {
        resBodySchema = mockToJsonSchema(item.handlers?.resBody?.mockRule, item)
    }
    // 如果有导入时的数据，则使用导入时的数据
    const importData = item?.importData
    const importMode = importData?.mode
    if (importMode) {
        // 这是swagger导入的
        if (importMode === ImportMode.swaggerJsonUrl && importData?.pathItem) {
            const methodItem =
                importData?.pathItem[item?.importData?.method || '']
            if (
                methodItem &&
                methodItem?.responses?.['200']?.content?.['application/json']
                    ?.schema
            ) {
                resBodySchema =
                    methodItem?.responses?.['200']?.content?.[
                        'application/json'
                    ]?.schema
            }
        } else if (
            importMode === ImportMode.yapiUrl ||
            importMode === ImportMode.yapiPage
        ) {
            let schema = importData?.yapiItem?.res_body
            if (typeof schema === 'string') {
                try {
                    schema = JSON.parse(schema)
                } catch {}
            }
            if (schema && typeof schema !== 'string') {
                // 从yapi导入的
                resBodySchema = schema
            }
        }
    }
    return resBodySchema
}

// 获取函数参数列表 - TypeScript
const getFuncParamsTs = (reqBodySchema: any, funcName: string) => {
    let result: string[] = []
    const keys = Object.keys(reqBodySchema?.properties || {})
    if (!keys?.length) return ''

    if (keys.length > 2) {
        return `params: I${funcName}ApiParams`
    }

    keys.forEach((key) => {
        result.push(`${key}: I${funcName}ApiParams['${key}']`)
    })
    return result.join(', ')
}

// 获取函数参数列表 - JavaScript
const getFuncParamsJs = (reqBodySchema: any, funcName: string) => {
    let result: string[] = []
    const keys = Object.keys(reqBodySchema?.properties || {})
    if (!keys?.length) return ''

    if (keys.length > 2) {
        return `params`
    }

    keys.forEach((key) => {
        result.push(key)
    })
    return result.join(', ')
}

const getFuncParamsJsDocStr = (reqBodySchema: any) => {
    if (!reqBodySchema) {
        return ''
    }

    // 只处理一层的情况，嵌套的情况暂时不考虑
    let res = '\n'
    const { properties } = reqBodySchema
    if (!properties) {
        return ''
    }
    const keys = Object.keys(properties)
    if (keys.length === 0) {
        return ''
    }
    let keyPrefix = ''
    // 参数大于3个时使用object
    if (keys.length > 2) {
        res += ` * @param { object } params 参数\n`
        keyPrefix = 'params.'
    }
    for (const key in properties) {
        const item = properties[key]
        let type = item.type
        if (!type) {
            continue
        }
        if (type === 'array') {
            type = `${item.items.type}[]`
        }
        type = type.replaceAll('integer', 'number')
        res += ` * @param { ${type} } ${keyPrefix}${key} ${item.description || ''}\n`
    }
    // 删除最后一个换行符
    res = res.slice(0, -1)
    return res
}

// 获取请求体data的内容
const getReqBodyData = (reqBodySchema: any) => {
    const keys = Object.keys(reqBodySchema?.properties || {})
    if (!keys?.length) return ''

    if (keys.length > 2) {
        return 'params'
    }

    return keys.join(', ')
}

export interface IMustacheDataItem {
    // 标题
    title: string
    // 请求方法
    method: string
    // 小写的方法名
    methodLower: string
    // 请求地址
    url: string | undefined
    // 大驼峰命名的函数名称
    funcName: any
    // TypeScript中的函数参数列表的定义
    funcParamsTs: string
    // JavaScript中的函数参数列表的定义
    funcParamsJs: string
    // 请求体data的内容
    reqBodyData: string
    // 请求参数的jsonSchema
    reqBodySchema: {}
    // 响应体的jsonSchema
    resBodySchema: {}
    // 请求参数的ts类型
    reqParamsTsInterface: string
    // 响应体ts类型
    resBodyTsInterface: string
    // 初始化示例响应体值
    initialExampleResValue: string
    // 请求参数的jsDoc字符串
    funcParamsJsDocStr: string
}

// 把apiItems转换为mustache模板数据
export const getMustacheData = async (
    apiItems: IApiItem[],
): Promise<IMustacheDataItem[]> => {
    const funcNames = getFuncNames(apiItems)
    const results: IMustacheDataItem[] = []
    for (const item of apiItems) {
        // 请求体和响应体的schema
        const reqBodySchema = getReqBodySchema(item)
        const resBodySchema = getResBodySchema(item)
        // 函数名称
        const funcName = funcNames[item.id] || 'Unknown'
        // 函数参数列表
        const funcParamsTs = getFuncParamsTs(reqBodySchema, funcName)
        // 参数数据
        const reqBodyData = getReqBodyData(reqBodySchema)
        // 函数参数列表 js
        const funcParamsJs = getFuncParamsJs(reqBodySchema, funcName)
        // 默认值
        const initialExampleResValue = sample(resBodySchema)
        const funcParamsJsDocStr = getFuncParamsJsDocStr(reqBodySchema)
        const initialExampleResValueString = JSON.stringify(
            initialExampleResValue,
            null,
            2,
        ).replaceAll('"string"', '""')
        const reqParamsTsInterface = await compile(
            reqBodySchema,
            `I${funcName}ApiParams`,
        )
        const resBodyTsInterface = await compile(
            resBodySchema,
            `I${funcName}ApiBody`,
        )

        const resItem = {
            // 标题
            title: item.label,
            // 请求方法
            method: lowerCase(item.method),
            // 小写的方法名
            methodLower: lowerCase(item.method),
            // 请求地址
            url: item.url,
            // 大驼峰命名的函数名称
            funcName: funcName,
            // 小驼峰命名的函数名称
            funcNameCamel: camelCase(funcName),
            // 请求参数的jsonSchema
            reqBodySchema,
            // 响应体的jsonSchema
            resBodySchema,
            // TypeScript中的函数参数列表的定义
            funcParamsTs,
            // 请求体data的内容
            reqBodyData,
            // JavaScript中的函数参数列表的定义
            funcParamsJs,
            // 请求参数的ts类型
            reqParamsTsInterface,
            // 响应体ts类型
            resBodyTsInterface,
            // 初始化示例响应体值
            initialExampleResValue: initialExampleResValueString,
            // 请求参数的jsDoc字符串
            funcParamsJsDocStr,
        }

        results.push(resItem)
    }
    return results
}
